# 2021年1月17日 星期日 下午15:13 日作业
# 人工智能学院1906A
# 裴云鹏

# 独立写一个餐厅系统。内容包括点餐，退餐，结账，评价四个功能。

from python_baway.common.xcommon import input_value_util_well

import random
import operator

# Let every run has a consistent result
random.seed(1)


def show_menu(numbers_arr):
    '''
    Show the menu

    :return: None
    '''
    print('可点菜品如下：')
    max_number_len = len(str(max(numbers_arr)))

    names_arr = [number2name_map.get(i, '') for i in numbers_arr]
    max_name = max(names_arr, key=lambda name: len(name), default=3)
    max_name_len = len(max_name)

    prices_arr = [number2price_map.get(i, '') for i in numbers_arr]
    max_price_str = max(prices_arr, key=lambda price: len('{:.2f}'.format(price)), default=4)
    max_price_len = len(f'{max_price_str:.2f}')

    for number in numbers_arr:
        name = number2name_map.get(number, '')
        # print('%d - %s - 每例%.2f元' % (order, name, ord2price_map[order]))
        xlen = len(name)

        # One chinese character is 2 times wider than a digit or english letter.
        # So, xlen * 2 + blanks = max_name_len * 2
        # So, length is xlen + blanks, i.e. xlen + (max_name_len-xlen)*2
        render = '{{order:>{order_len}d}} {{name:<{name_len}s}} {{price:>{price_len}.2f}}' \
            .format(order_len=max_number_len, name_len=xlen + (max_name_len - xlen) * 2, price_len=max_price_len)
        render = render.format(order=number, name=name, price=number2price_map[number])
        print(render)
    print()


def order_dish(order):
    '''
    Specify a order of dish.

    :param order: The number of the dish.
    :return: None
    '''
    if order in ordered_number2mul_map.keys():
        ordered_number2mul_map[order] += 1
    else:
        ordered_number2mul_map[order] = 1


def show_ordered():
    '''
    Show the user which dishes she has already ordered and the money she need to pay.

    :return: The total money the user should pay.
    '''
    if len(ordered_number2mul_map) <= 0:
        print('您还没有点菜')
        return 0
    print('您的预定如下：')
    xsum = 0
    print(type(sorted(ordered_number2mul_map.items(), key=operator.itemgetter(0))))  # for debug
    for number, mul in sorted(ordered_number2mul_map.items(), key=operator.itemgetter(0)):
        price = number2price_map[number] * mul
        xsum += price
        print(f'\
{number} 号菜品 {number2name_map.get(number, "????")} \
{number2price_map.get(number, 0):.2f}元每例 共{mul}例，{price:.2f}元')
    print('您一共消费%.2f元。' % xsum)
    return xsum


# the menu
menu = ['清蒸鲈鱼', '宫保鸡丁', '鱼香肉丝', '蚂蚁上树',
        '水煮肉片', '西红柿炖牛腩', '干锅牛蛙', '杀猪菜',
        '西红柿炒鸡蛋', '炒米', '佛跳墙', '羊肉汤', '肉夹馍']
menu_len = len(menu)

# the maps
number2price_map = {}
number2name_map = {}
tup = enumerate(menu, 1)
for order, name in tup:
    price = float(100 * order * random.random() // 10 * 10 + 10)  # the prices of each dish
    number2price_map[order] = price
    number2name_map[order] = name.strip()
print(number2name_map)
print(number2price_map)

all_numbers_arr = list(number2name_map.keys())  # numbers of available dishes

all_numbers_sorted_asc = all_numbers_arr.copy()  # numbers of available dishes sorted by price asc
all_numbers_sorted_asc.sort(key=lambda ord: number2price_map.get(ord, 0))

all_numbers_sorted_desc = all_numbers_sorted_asc.copy()  # desc
all_numbers_sorted_desc.reverse()

# main functions
main_opts_arr = ['点菜退餐',
                 '结账',
                 '留言',
                 '查看留言',
                 '退出']
main_opts_arr_len = len(main_opts_arr)
promptStr = '-' * 32 + '\n'
for i, j in enumerate(main_opts_arr):
    promptStr += f'{i + 1} - {j}\n'

# main loop
ordered_number2mul_map = {}  # ordered dishes
comments = []  # comments
while True:
    print(promptStr)
    choice = input_value_util_well(int, '请选择：',
                                   ((lambda ch: 1 <= ch <= main_opts_arr_len), '输入有误！请按序号选择！'),
                                   xerror_prompt='输入有误！请重新选择！')

    # last function, always be exit
    n = main_opts_arr_len
    if n == choice:  # quit
        print('欢迎再来！')
        break

    # previous function, check comments
    n -= 1
    if n == choice:
        if len(comments) == 0:
            print('暂无评论。')
        else:
            print('以往顾客评论如下：')
            for c in comments:
                print(f'\t>{c}')
        continue

    # previous function, comment
    n -= 1
    if n == choice:
        comment = input('请留下您宝贵的评论：').strip()
        if len(comment) > 0:
            comments.append(comment)
        else:
            print('您并没有留下评论。')
        continue

    # previous function, pay
    n -= 1
    if n == choice:
        xsum = show_ordered()
        if xsum <= 0:
            continue
        xpaied = 0
        while True:
            if xpaied >= xsum:
                if xpaied == xsum:
                    print('您的餐费已结清。')
                elif xpaied > xsum:
                    print('请拿好找零：%.2f元' % (xpaied - xsum))
                ordered_number2mul_map = {}
                break
            else:
                xpay = input_value_util_well(float, '请收银美眉收款：',
                                   ((lambda x: x > 0), '别开玩笑了！'),
                                   xerror_prompt='输入有误，请重新输入！')
                if xpay is None:
                    continue
                xpaied += xpay
                if xpaied < xsum:
                    print('您的付款不够呢！还差%.2f元。' % (xsum - xpaied))
        continue

    # previous function, order and cancel
    n -= 1
    if n == choice:
        while True:
            if len(ordered_number2mul_map):
                show_ordered()
            else:
                print('您目前没有点菜，请输入序号进行点菜。')
            ch = input('\
您点什么？(输入0结束, 输入m查看菜单，m1按价格升序查看菜单，m2按价格降序，c查看已选菜品详情，\
输入a全点，输入r1 r2 r3...按菜品号码删除，ra进行清空。)').strip()
            if 'm' == ch:
                show_menu(all_numbers_arr)
                continue
            elif 'm1' == ch:
                show_menu(all_numbers_sorted_asc)
                continue
            elif 'm2' == ch:
                show_menu(all_numbers_sorted_desc)
                continue
            elif 'c' == ch:
                continue
            elif 'a' == ch:
                for order in number2name_map.keys():
                    order_dish(order)
                continue
            elif 'ra' == ch:
                ordered_number2mul_map.clear()
                print('您的预定已清空。')
                continue
            elif len(ch) >= 2 and 'r' == ch[0]:
                try:
                    tgt = int(ch[1:])
                except ValueError:
                    print('输入有误！')
                    continue
                if not (tgt in number2name_map):
                    print('删除失败！请按菜单序号！')
                    continue
                try:
                    mul = ordered_number2mul_map.get(tgt, 0)
                    del ordered_number2mul_map[tgt]
                    print('已经移除{0}例"{name}"'.format(mul, name=number2name_map[tgt]))
                except KeyError:
                    print('删除失败！您并没有点：', tgt, number2name_map[tgt])
                    continue
                continue
            try:
                ch = int(ch)
            except ValueError:
                print('输入有误！')
                continue
            if ch == 0:
                break
            if not (ch in number2name_map):
                print('输入有误！请按菜单序号点菜！')
                continue
            order_dish(ch)
        continue
